import java.util.ArrayList;
import org.json.JSONException;
import java.io.BufferedReader;
import java.io.IOException;

/*
 * Загрузка AVL дерева из JSON файла специального формата. Данные должны быть
 * представлены как JSON массивы, разделененные переводами строк.
 * Одна строка - это один узел дерева.
 */
final public class TreeJSONReader<T> implements TreeReader<T> {

    BufferedReader reader;
    StringBuilder token_b = new StringBuilder(50);
    ArrayList<Object> data = new ArrayList<Object>(10);
    int pos;
    String line;
    int lineNumber = 0;

    TreeJSONReader(BufferedReader reader) {
        this.reader = reader;
    }

    @Override
    public boolean next() throws IOException {
        line = reader.readLine();
        data.clear();
        lineNumber++;
        pos = 1;
        return (line != null);
    }

    @Override
    public boolean isDelimiter() {
        return line.startsWith("===");
    }

    @Override
    public ArrayList<Object> parse1() {
        if (line.charAt(0) != '[' || line.charAt(line.length()-1) != ']')
            throw new JSONException("Expected '[' and ']' at line "+lineNumber);

        int token_n = 0;
        for (; pos < line.length()-1; pos++) {
            char c = line.charAt(pos);
            if (c == ',') {
                String token = token_b.toString();
                if (token_n < 3) {
                    if (!token.equals("null")) {
                        Integer value = Integer.valueOf(token.toString());
                        data.add(value);
                    } else {
                        data.add(null);
                    }
                } else if (token_n == 3) {
                    if (!token.equals("null")) {
                        Integer value = Integer.valueOf(token.toString());
                        data.add(value);
                    } else {
                        data.add(null);
                    }
                    token_n++;
                    token_b.setLength(0);
    
                    pos++;
                    if (line.charAt(pos++) != '\"') {
                        throw new JSONException("Expected '\"' at position "+ pos + " line "+lineNumber);
                    }
                    c = line.charAt(pos);
                    char c1 = line.charAt(pos-1);
                    while (c != '"' || c1 == '\\') {
                        token_b.append(c);
                        c1 = c;
                        c = line.charAt(++pos);
                    }
                    pos += 1;
                    data.add(new Word(token_b.toString()));
                    token_b.setLength(0);
                    return data;
                }
                token_n++;
                token_b.setLength(0);
            } else {
                token_b.append(c);
            }
        }
        throw new JSONException("Unexpected end of line");
    }

    @Override
    public ArrayList<Object> parseWord() {
        if (line.charAt(pos++) != ',') {
            throw new JSONException("Expected ',' at position "+ pos + " line "+lineNumber);
        }
        if (line.charAt(pos++) != '{') {
            throw new JSONException("Expected '{' at position "+ pos + " line "+lineNumber);
        }
        if (line.charAt(pos++) != '"') {
            throw new JSONException("Expected '\"' at position "+ pos + " line "+lineNumber);
        }
        char type = line.charAt(pos++);
        if (type != 'W' && type != 'U' && type != 'S') {
            throw new JSONException("Wrong Word type at position "+ pos + " line "+lineNumber);
        }
        if (line.charAt(pos++) != '"') {
            throw new JSONException("Expected '\"' at position "+ pos + " line "+lineNumber);
        }
        if (line.charAt(pos++) != ':') {
            throw new JSONException("Expected ':' at position "+ pos + " line "+lineNumber);
        }
        token_b.setLength(0);
        if (line.charAt(pos) != '"') {
            char c = line.charAt(pos);
            while (Character.isDigit(c)) {
                token_b.append(c);
                c = line.charAt(++pos);
            }
        } else {
            char c = line.charAt(++pos);
            char c1 = line.charAt(pos-1);
            while (c != '"' || c1 == '\\') {
                token_b.append(c);
                c1 = c;
                c = line.charAt(++pos);
            }
            pos++;
        }
        data.add(WordInterface.fromString(type, token_b.toString()));
        token_b.setLength(0);
        if (line.charAt(pos++) != '}') {
            throw new JSONException("Expected '}' at position "+ pos + " line "+lineNumber);
        }
        return data;
    }

    @Override
    public ArrayList<Object> parseDataArray() {
        if (line.charAt(pos++) != ',')
            throw new JSONException("Expected ',' at position "+ pos + " line "+lineNumber);

        if (line.charAt(pos) != '[' || line.charAt(line.length()-2) != ']')
            throw new JSONException("Expected '[' and ']' at line "+lineNumber);

        int delim = line.indexOf("],[", pos);
        String str1 = line.substring(pos+1, delim);
        String str2 = line.substring(delim+3, line.length()-2);
        String[] ar1 = str1.split(",");
        String[] ar2 = (str2.length() > 0) ? str2.split(",") : null;
        Object[] a1 = new Object[ar1.length];
        for (int i = 0; i < ar1.length; i++)
            a1[i] = Integer.valueOf(ar1[i]);
        data.add(a1);
        data.add(ar2);
        return data;
    }

    @Override
    public ArrayList<Object> parseIndexArray() {
        if (line.charAt(pos++) != ',') {
            throw new JSONException("Expected ',' at position "+ pos + " line "+lineNumber);
        }
        if (line.charAt(pos) != '[' || line.charAt(line.length()-2) != ']')
            throw new JSONException("Expected '[' and ']' at line "+lineNumber);

        String str = line.substring(pos+1, line.length()-2);
        String[] ar = str.split(",");
        Object[] a = new Object[ar.length];
        for (int i = 0; i < ar.length; i++)
            a[i] = Integer.valueOf(ar[i]);
        data.add(a);
        return data;
    }
}